package com.united.ucts.modules.monitor.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.united.frame.common.util.DateUtil;
import com.united.ucts.modules.monitor.pojo.*;
import com.united.ucts.modules.monitor.service.ServerMonitorService;
import org.springframework.stereotype.Service;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor.TickType;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;

import java.lang.management.ManagementFactory;
import java.util.*;

import static com.united.frame.common.util.FileUtil.convertFileSize;

/**
 * 服务器监控信息业务逻辑处理接口实现类
 *
 * @author Hudan
 * @version 1.0
 * @filename ServerMonitorServiceImpl.java
 * @copyright <a href="www.united.cn">www.united.cn</a>
 * @date 2019/7/22
 */
@Service
public class ServerMonitorServiceImpl implements ServerMonitorService {

    /**
     * 获取服务器信息
     *
     * @return 服务运行的服务器信息
     */
    @Override
    public ServerInfo getServer() {
        // 初始化系统信息
        SystemInfo si = new SystemInfo();

        ServerInfo server = new ServerInfo();
        server.setJvm(getJvm());
        server.setSys(getSys(si));
        server.setLstFileSys(getFilesys(si));
        server.setCpu(getCpu(si));
        server.setMem(getMem(si));
        return server;
    }

    /**
     * 获取当前服务的内存信息
     *
     * @param si 当前服务所在服务器信息
     * @return 内存信息
     */
    private Memory getMem(SystemInfo si) {
        Memory mem = new Memory();

        HardwareAbstractionLayer hal = si.getHardware();
        mem.setTotal(hal.getMemory().getTotal());
        mem.setUsed(hal.getMemory().getTotal() - hal.getMemory().getAvailable());
        mem.setFree(hal.getMemory().getAvailable());

        mem.setJvmTotal(Runtime.getRuntime().totalMemory());
        mem.setJvmFree(Runtime.getRuntime().freeMemory());

        return mem;
    }

    /**
     * 获取CPU信息
     *
     * @param si 当前服务所在服务器信息
     * @return CPU信息
     */
    private Cpu getCpu(SystemInfo si) {
        Cpu cpu = new Cpu();

        HardwareAbstractionLayer hal = si.getHardware();
        // CPU信息
        long[] prevTicks = hal.getProcessor().getSystemCpuLoadTicks();
        Util.sleep(1000);
        long[] ticks = hal.getProcessor().getSystemCpuLoadTicks();
        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
        cpu.setCpuNum(hal.getProcessor().getLogicalProcessorCount());
        cpu.setTotal(totalCpu);
        cpu.setSys(cSys);
        cpu.setUsed(user);
        cpu.setWait(iowait);
        cpu.setFree(idle);

        return cpu;
    }

    /**
     * 获取当前服务运行的服务器的文件系统信息
     *
     * @param si 当前服务所在服务器信息
     * @return 服务器的文件系统信息
     */
    private List<FileSys> getFilesys(SystemInfo si) {

        List<FileSys> lstFileSys = new ArrayList<>();

        OperatingSystem os = si.getOperatingSystem();
        FileSystem fileSystem = os.getFileSystem();
        List<OSFileStore> fileStores = fileSystem.getFileStores();
        for (OSFileStore fs : fileStores) {
            long free = fs.getUsableSpace();
            long total = fs.getTotalSpace();
            long used = total - free;
            FileSys fileSys = new FileSys();
            fileSys.setDirName(fs.getMount());
            fileSys.setSysTypeName(fs.getType());
            fileSys.setTypeName(fs.getName());
            fileSys.setTotal(convertFileSize(total));
            fileSys.setFree(convertFileSize(free));
            fileSys.setUsed(convertFileSize(used));
            fileSys.setUsage(NumberUtil.mul(NumberUtil.div(used, total, 4), 100));
            lstFileSys.add(fileSys);
        }

        // 排序
        lstFileSys.sort(Comparator.comparing(FileSys::getDirName));

        return lstFileSys;
    }

    /**
     * 获取当前服务运行的Java虚拟机信息
     *
     * @return Java虚拟机信息
     */
    private Jvm getJvm() {
        // 虚拟机运行时间
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        // 系统运行时参数
        Properties props = System.getProperties();

        Jvm jvm = new Jvm();
        jvm.setName(ManagementFactory.getRuntimeMXBean().getVmName())
                .setVersion(props.getProperty("java.version"))
                .setHome(props.getProperty("java.home"))
                .setUserDir(props.getProperty("user.dir"))
                .setStartTime(DateUtil.formatTime(new Date(time)))
                .setRunTime(DateUtil.getDateDiff(new Date(), new Date(time)));
        return jvm;
    }

    /**
     * 获取服务器信息
     *
     * @param si 服务器信息
     * @return 服务器信息
     */
    private Sys getSys(SystemInfo si) {
        HardwareAbstractionLayer hal = si.getHardware();
        Properties props = System.getProperties();
        Sys sys = new Sys();
        sys.setCore(String.valueOf(hal.getProcessor().getPhysicalProcessorCount()));
        sys.setCpus(String.valueOf(hal.getProcessor().getLogicalProcessorCount()));
        sys.setName(hal.getComputerSystem().getModel());
        sys.setProductor(hal.getComputerSystem().getManufacturer());
        sys.setOs(props.getProperty("os.name"));
        sys.setStructure(props.getProperty("os.arch"));
        return sys;
    }
}